home *** CD-ROM | disk | FTP | other *** search
- /*
- *
- * This code is NOT from Berkley, but FROM ME :-)
- *
- * Very stupid Arexx ping.
- * Don't use it to ping localhost or you would ROTFL.
- *
- * Usage: ping <HOST> [SIZE/N] [NUM/N] [QUICK/S]
- *
- * HOST - the host name to ping
- * SIZE - the size of the imcp echo packet
- * NUM - the number of packet to send - 0 means continuos
- * QUICK - don't delay, send as fast as possible
- *
- */
-
- signal on halt
- signal on break_c
-
- call init()
- call start()
- signal break_c
-
- /********************************************************************/
- init: procedure expose global.
- l="rmh.library";if ~show("L",l) then;if ~addlib(l,0,-30) then exit
- if AddLibrary("rexxsupport.library","rxsocket.library")~=0 then exit
- global.prg = ProgramName("NoExt")
-
- /** read and parse arguments **/
- template="HOST/A,SIZE/K/N,NUM/K/N,QUICK/S"
- help="
- ping 2.0 by Alfonso Ranieri" || "a"x || "
- Usage:" global.prg "<HOST> [SIZE/K/N] [NUM/K/N] [QUICK/S] [HELP/S] [VERSION/S]" || "a"x || "
- HOST the host to ping" || "a"x || "
- SIZE the SIZE of the packet to send (7<SIZE<8000)" || "a"x || "
- NUM how many packet" || "a"x || "
- QUICK sends packet as fatest as possible" || "a"x
-
- if ~RMH_ReadArgs(template,help) then do
- call PrintFault()
- exit
- end
-
- if parm.1.flag then
- if parm.1.value>7 & parm.1.value<8000 then global.dataSize=parm.1.value
- else call err("SIZE must be >7 and <8000")
- else global.dataSize=56
-
- if parm.2.flag then
- if parm.2.value>0 then global.numPkt=parm.2.value
- else call err("NUM must be positive")
- else global.numPkt=1E10
-
- global.wait=~parm.3.flag
-
- global.break=0
-
- /** resolve host name **/
- global.host=parm.0.value
- global.sin.addrAddr=resolve(global.host)
- if global.sin.addrAddr=="-1" then call err "host <"global.host"> not found"
-
- /** create a RAW ICMP socket **/
- global.sock=socket("INET","RAW","ICMP")
- if global.sock<0 then call err("no socket")
-
- /** socket must NOT blocking **/
- call IOCtlSocket(global.sock,"FIONBIO",1)
-
- /** we need an ID to recognize our icmp **/
- global.ourID=right(x2c(pragma("ID")),2)
-
- /** init globals */
- global.min=1E10
- global.max=0
- global.avg=0
- global.nrec=0
- global.ntrans=0
-
- /** create a timer **/
- global.tim=CreateTimer()
- global.ts=TimerSignal(global.tim)
-
- return
- /********************************************************************/
- start: procedure expose global.
- if global.numPkt==1E10 then global.ps=""
- else global.ps=" Num:" global.numPkt
- say global.PRG global.host "("global.sin.addrAddr"):" global.dataSize "data bytes" global.ps
-
- /** Here we go:
- wait_for_packet_or_time_to_send
- readpacket if any
- sendpacket if time
- **/
-
- call StartTimer(global.tim,global.wait)
- call sendPacket
- global.sel.read.0=global.sock
- go=global.ntrans<global.numPkt | global.numPkt==1
- do while go
-
- res=WaitSelect("global.sel",,,global.ts)
- if res~=0 then call readPacket
-
- if and(global.sel.signals,global.ts)~=0 then do
- call sendPacket
- if global.wait==0 then call WriteCH("STDOUT",".")
- call StartTimer(global.tim,global.wait)
- end
- go=global.ntrans<global.numPkt
- end
- return
- /********************************************************************/
- err: procedure expose global.
- parse arg msg
- say global.prg":" msg
- exit
- /********************************************************************/
- pad: procedure
- parse arg string,len
- return copies(d2c(0),len-length(string)) || string
- /********************************************************************/
- d2m: procedure
- parse arg val,len
- return pad(d2c(val),len)
- /********************************************************************/
- sendPacket: procedure expose global.
- /** here we create an ICMP echo packet **/
- pktf = global.ourID || d2m(global.ntrans,2)
- call GetSysTime("TV")
- pktf=pktf || d2m(tv.secs,4) || d2m(tv.micro,4) || copies("0"x,global.dataSize-8)
- temp="0800"x || "0000"x || pktf
- pkt="0800"x || d2c(InetCksum(temp)) || pktf
- if sendto(global.sock,pkt,0,"global.sin")<0 then call err("sendto error ("ErrorString()")")
- global.ntrans=global.ntrans+1
- return
- /********************************************************************/
- readPacket: procedure expose global.
- /** here we read an ICMP packet and check if it is an ICMP
- echo-replay for us **/
- call GetSysTime("NOW")
- res=recvfrom(global.sock,"BUFF",256)
- if res<0 then call call err("recvfrom error ("ErrorString()")")
- parse var buff vhl +1 tos +1 len +2 id +2 off +2 ttl +1 rest
- hl=c2d(bitand(vhl,'F'x))*8
- buff=c2x(buff)
- parse var buff +hl type +2 code +2 cksum +4 id +4 seq +4 s +8 m +8 data
- if c2d(len)~=global.dataSize+8 | type~='00' | code~='00' | id~=c2x(global.ourID)
- then return
- old.secs=x2d(s)
- old.micro=x2d(m)
- call SubTime("NOW","OLD")
- time=now.secs*1000000+now.micro
- time=time%1000"."time//1000
- time=((time*100)%1)/100
- if global.wait==1 then
- say c2d(len) "bytes from" global.sin.AddrAddr": icmp_seq="x2d(seq) "ttl="c2d(ttl) "time="time "ms"
- global.nrec=global.nrec+1
- if time>global.max then global.max=time
- if time<global.min then global.min=time
- global.avg=global.avg+time
- return
- /********************************************************************/
- /** statistics **/
- halt:
- break_c:
- if break==1 | sigl<38 then call err("user break")
- if t~="T" then call StopTimer(global.tim)
- break=1
- signal on break_c
- if global.ntrans>global.nrec & global.max>0 then do
- res=WaitSelect("global.sel",5)
- if res~=0 then call readPacket
- end
- if ntrans==0 then loss=100
- else loss=(global.ntrans-global.nrec)/global.ntrans*100
- say
- say "---" global.host "ping statistics ---"
- say global.ntrans "packets transmitted," global.nrec "packets received," loss"% packet loss"
- if global.nrec>0 then say "round-trip min/avg/max =" global.min"/"|| (((global.avg/global.nrec)*100)%1)/100 || "/"global.max "ms"
- exit
- /********************************************************************/
-